import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.Base64;
import java.util.Scanner;

/**
 * 基于java实现的RSA加密解密和SHA512哈希摘要计算实现模拟数字签名
 *
 * @author: wyb
 * @Description:
 * @Encoding: UTF-8
 * @create: 2021/11/27 21:48
 *
 * RSA加密解密 及 SHA512哈希摘要计算的具体实现看javaRSA_SHA512.java
 *
 **/
public class javaDigitalSignature {

    // 原文
    private static String text;
    // RSA加密摘要得到的数字证书
    private static String encodeDigest;
    // RSA解密得到的摘要
    private static String decodeDigest;


    // 修改原文
    private static void changeText(){
        text = text + "333";
    }

    // 修改数字签名
    private static void changeDigitalSignature(){
        StringBuilder sb = new StringBuilder(encodeDigest);
        sb.setCharAt(0, 'a');
        sb.setCharAt(1, 'a');
        sb.setCharAt(2, 'a');
        sb.setCharAt(3, 'a');
        encodeDigest = sb.toString();
    }

    // 验证数字签名
    private static boolean verify(){
        return decodeDigest.equals(javaRSA_SHA512.SHA512(text));
    }

    public static void main(String[] args) throws NoSuchPaddingException, NoSuchAlgorithmException, IllegalBlockSizeException, BadPaddingException, InvalidKeyException {

        // ======================================================
        // 模拟发送方
        // 输入原文
        System.out.print("请输入原文:");
        Scanner input = new Scanner(System.in);
        text = input.nextLine();
        System.out.println("原文为: " + text);

        // 通过SHA-512算法计算摘要
        String digest = javaRSA_SHA512.SHA512(text);
        System.out.println("获得消息摘要(SHA512摘要): " + digest);

        // 对摘要进行RSA加密
        Cipher cipher = javaRSA_SHA512.initRSA();

        // RSA加密调用方法
        byte[] cipherbytes = javaRSA_SHA512.RSAEncode(cipher, digest);
        // 注意: 这里必须要用Base64进行编码 否则会乱码
        encodeDigest = Base64.getEncoder().encodeToString(cipherbytes);
        System.out.println("获得密文(RSA加密后的密文): " + encodeDigest);

        // ======================================================
        // 模拟数字签名验证失败的情况 => 模拟攻击者
        // 1、修改原文
        // changeText();
        // 2、修改数字签名
        // changeDigitalSignature();

        // ======================================================
        // 模拟接收方

        // RSA解密调用方法
        // 注意这里要用Base64进行解码 得到bytes数组
        try {
            decodeDigest = javaRSA_SHA512.RSADecode(cipher, Base64.getDecoder().decode(encodeDigest));
            System.out.println("解密的消息摘要(RSA解密后的明文, 即消息摘要): " + decodeDigest);
        } catch (BadPaddingException e){
            System.out.println("无法解密出消息摘要, 数字签名验证失败");
        }

        if (verify()){
            System.out.println("数字签名验证通过");
        } else{
            System.out.println("数字签名验证失败");
        }


    }

}
